package com.sangmo.boot.auth.core;

import com.sangmo.boot.auth.core.repo.AuthorizeCodeRepo;
import com.sangmo.boot.auth.core.handlers.AuthorizeCodeHandler;
import com.sangmo.boot.auth.core.interfaces.GrantCodeRequest;
import com.sangmo.boot.auth.core.model.AuthorizeCode;
import com.sangmo.boot.framework.common.errors.ServiceException;
import com.sangmo.boot.framework.common.errors.StandardErrors;
import com.sangmo.boot.framework.plugin.dataview.crud.service.BaseViewService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;


@Service
public class AuthorizeCodeService extends BaseViewService<AuthorizeCode> {

	@Autowired
	private AuthorizeCodeRepo repo;
	@Autowired
	protected ClientService clientService;

	@Override
	public AuthorizeCodeRepo getRepo() {
		return repo;
	}

	@Autowired(required=false)
	@Qualifier("codeClientHandlers")
	private Map<String, AuthorizeCodeHandler> handlerRegister = new HashMap<>();

	private AuthorizeCodeHandler findHandlerForClient(String clientId) {
		AuthorizeCodeHandler handler = handlerRegister.get(clientId);
		if (null == handler) {
			handler = handlerRegister.get("default");
		}
		return handler;
	}

	public void grant(GrantCodeRequest req) {
		AuthorizeCodeHandler handler = findHandlerForClient(req.getClientId());
		handler.grant(req);
	}

	public boolean validate(String clientId, String username, String code, String randomStr) {
		AuthorizeCode authorizeCode = this.findByClientIdAndUsername(clientId, username);
		if (null != code) {
			if (authorizeCode.getFailure() > AuthorizeCode.MAX_FAILURE) {
				throw new ServiceException(StandardErrors.AUTHORIZED_WRONG.getStatus(), "error.authcode.exeeds.failure", AuthorizeCode.MAX_FAILURE);
			}
			if (authorizeCode.isExpired()) {
				throw new ServiceException(StandardErrors.AUTHORIZED_WRONG.getStatus(), "error.authcode.expired", authorizeCode.getValidity());
			}

			if (authorizeCode.getCode().equals(code) && authorizeCode.getRandomStr().equals(randomStr)) {
				authorizeCode.setUsedTime(new Date());
				this.save(authorizeCode);
				return true;
			} else {
				this.updateFail(authorizeCode);
				return false;
			}
		}
		return false;
	}

	public void updateFail(AuthorizeCode code) {
		//code.setFailure(code.getFailure() + 1);
		this.repo.increaseFailure(code.getId());
	}

	public AuthorizeCode findByClientIdAndUsername(String clientId, String username) {
		return repo.findOneByClientIdAndUsername(clientId, username);
	}
}
